#include "SerialSocket.hpp"
#include "List.hpp"
#include <string.h>
#include "crc16.hpp"

class __SerialSockets;

class __SerialSocket : public SerialSocket{
public:
    explicit __SerialSocket(__SerialSockets *serial_sockets,int port_number);
    virtual ~__SerialSocket();
    virtual bool open();
    virtual bool close();
    virtual unsigned int read(void *buffer,unsigned int size);
    virtual unsigned int write(const void *buffer,unsigned int size);
    virtual int getPortNumber();
public:
    __SerialSockets *serial_sockets;
    int port_number;
    char *rx_buffer;
    int rx_sem_number;
    int expected_packet;
    int rx_size;
    int rx_max_size;
};

class __SerialSockets : public SerialSockets{
public:
    explicit __SerialSockets(SerialSocketPortable *portable,unsigned int buffer_size);
    virtual ~__SerialSockets();
    virtual bool open();
    virtual bool close();
    virtual SerialSocket *get(int port_number);
    virtual bool free(SerialSocket *instance);
    virtual unsigned int writePort(int port_number,const void *buffer,unsigned int size);
    virtual void eventHandler();
public:
    SerialSocketPortable *portable;
private:
    char *tx_buffer;
    char *rx_buffer;
    char *resp_buffer;
    int buffer_size;
    int tx_sem_number;
    int tx_resp_sem_number;
    uint16_t tx_resp_code;
    List<__SerialSocket*> serial_socket_list;
    bool writing;
};

/************ __SerialSocket相关方法 ************/

/************
 *  @fn     __SerialSocket::__SerialSocket(__SerialSockets *serial_sockets,int port_number);
 *  @brief  __SerialSocket类构造函数
 *  @param  serial_sockets  SerialSocket所归属的SerialSockets
 *  @param  port_number     所使用的端口号
 */
__SerialSocket::__SerialSocket(__SerialSockets *serial_sockets,int port_number){
    this->serial_sockets = serial_sockets;
    this->port_number = port_number;
    this->rx_buffer = nullptr;
    this->rx_size = 0;
    this->expected_packet = -1;
    if ( this->serial_sockets->portable != nullptr ){
        this->rx_sem_number = this->serial_sockets->portable->getSemaphore(false);
    }else{
        this->rx_sem_number = -1;
    }
}

/************
 *  @fn     __SerialSocket::~__SerialSocket();
 *  @brief  __SerialSocket的析构函数.
 */
__SerialSocket::~__SerialSocket(){
    if ( this->serial_sockets == nullptr ){
        return;
    }
    if ( this->serial_sockets->portable == nullptr ){
        return;
    }
    /* 删除信号量. */
    this->serial_sockets->portable->freeSemaphore(this->rx_sem_number);
}

/************
 *  @fn     bool __SerialSocket::open();
 *  @brief  打开SerialSocket
 *  @return 返回打开操作的结果
 */
bool __SerialSocket::open(){
    /* 该方法不做处理,返回真. */
    return true;
}

/************
 *  @fn     bool __SerialSocket::close();
 *  @brief  关闭SerialSocket
 *  @return 返回关闭操作的结果
 */
bool __SerialSocket::close(){
    /* 该方法不做处理,返回真. */
    return true;
}

/************
 *  @fn     unsigned int __SerialSocket::read(void *buffer,unsigned int size);
 *  @brief  从端口读取指定长度的数据
 *  @param  buffer  接收的数据缓冲区
 *  @param  size    接收的最大长度
 *  @return 接收的实际长度
 */
unsigned int __SerialSocket::read(void *buffer,unsigned int size){
    if ( this->serial_sockets == nullptr ){
        return 0;
    }
    if ( this->serial_sockets->portable == nullptr ){
        return 0;
    }
    if ( buffer == nullptr || size == 0 ){
        return 0;
    }
    /* 注册需要接收数据的缓冲区. */
    this->rx_buffer = (char*)buffer;
    this->rx_max_size = size;
    this->expected_packet = -1;
    this->rx_size = 0;
    this->serial_sockets->portable->takeSemaphore(this->rx_sem_number,-1);
    /* 清除注册. */
    this->rx_buffer = nullptr;
    this->rx_max_size = 0;
    return this->rx_size;
}

/************
 *  @fn     unsigned int __SerialSocket::write(void *buffer,unsigned int size);
 *  @brief  向端口写入指定长度的数据
 *  @param  buffer  发送的数据缓冲区
 *  @param  size    发送的长度
 *  @return 发送的实际长度
 */
unsigned int __SerialSocket::write(const void *buffer,unsigned int size){
    if ( this->serial_sockets == nullptr ){
        return 0;
    }
    return this->serial_sockets->writePort(this->port_number,buffer,size);
}

/************
 *  @fn     int __SerialSocket::getPortNumber();
 *  @brief  获取当前SerialSocket所使用的端口号
 *  @return 当前SerialSocket所使用的端口号
 */
int __SerialSocket::getPortNumber(){
    return this->port_number;
}

/************ __SerialSockets相关方法 ************/

/************
 *  @fn     __SerialSockets::__SerialSockets(SerialSocketPortable *portable)
 *  @brief  __SerialSockets的构造函数
 *  @param  portable    SerialSockets的移植接口实现
 */
__SerialSockets::__SerialSockets(SerialSocketPortable *portable,unsigned int buffer_size){
    this->portable = portable;
    /* 获取Semaphore. */
    this->tx_sem_number = this->portable->getSemaphore(true);
    if ( this->tx_sem_number < 0 ){
        /* 如果tx_sem_number < 0说明没有成功申请到信号量. */
        return;
    }
    this->tx_resp_sem_number = this->portable->getSemaphore(false);
    if ( this->tx_resp_sem_number < 0 ){
        /* tx_resp_sem_number < 0说明没有成功申请到信号量. */
        return;
    }
    /* 释放信号量. */
    this->portable->releaseSemaphore(this->tx_sem_number);
    /* 创建发送缓冲区. */
    if ( buffer_size < SS_MAX_PAYLOAD_SIZE + sizeof(SerialSocketFrameHeader) + 2 ){
        buffer_size = SS_MAX_PAYLOAD_SIZE + sizeof(SerialSocketFrameHeader) + 2;
    }
    this->buffer_size = buffer_size;
    this->tx_buffer = new char[this->buffer_size];
    this->rx_buffer = new char[this->buffer_size];
    this->resp_buffer = new char[sizeof(SerialSocketFrameHeader) + 2];
    this->writing = false;
}

__SerialSockets::~__SerialSockets(){
    if ( this->resp_buffer != nullptr ){
        delete[] this->resp_buffer;
        this->resp_buffer = nullptr;
    }
    if ( this->rx_buffer != nullptr ){
        delete[] this->rx_buffer;
        this->rx_buffer = nullptr;
    }
    if ( this->tx_buffer != nullptr ){
        delete[] this->tx_buffer;
        this->tx_buffer = nullptr;
    }
    if ( this->portable != nullptr ){
        this->portable->freeSemaphore(this->tx_sem_number);
        this->portable->freeSemaphore(this->tx_resp_sem_number);
    }
}

/************
 *  @fn     bool __SerialSockets::open();
 *  @brief  打开SerialSockets,初始化硬件
 *  @return 打开操作的结果
 */
bool __SerialSockets::open(){
    if ( this == nullptr ){
        return false;
    }
    if ( this->portable == nullptr ){
        return false;
    }
    if ( !this->portable->open() ){
        return false;
    }
    return true;
}

/************
 *  @fn     bool __SerialSockets::close();
 *  @brief  关闭SerialSockets.
 *  @return 关闭操作的结果
 */
bool __SerialSockets::close(){
    if ( this == nullptr ){
        return false;
    }
    if ( this->portable == nullptr ){
        return false;
    }
    if ( !this->portable->close() ){
        return false;
    }
    return true;
}

/************
 *  @fn     SerialSocket *__SerialSockets::get(int port_number);
 *  @brief  从SerialSocket中获取指定的SerialSocket
 *  @param  port_number     端口号
 *  @return 获取的SerialSocket.若无法获取，则返回nullptr.
 */
SerialSocket *__SerialSockets::get(int port_number){
    if ( this == nullptr ){
        return nullptr;
    }
    if ( this->portable == nullptr ){
        return nullptr;
    }
    /* 检查端口是否被占用. */
    for ( int n = 0; n < this->serial_socket_list.getSize(); n++ ){
        __SerialSocket *serial_socket = this->serial_socket_list.get(n);
        if ( serial_socket != nullptr ){
            if ( serial_socket->getPortNumber() == port_number ){
                /* 端口被占用. */
                return nullptr;
            }
        }
    }

    /* 创建对象. */
    __SerialSocket *serial_socket = new __SerialSocket(this,port_number);
    
    /* 注册资源. */
    this->serial_socket_list.append(serial_socket);
    return serial_socket;
}

/************
 *  @fn     bool __SerialSockets::free(SerialSocket *instance);
 *  @brief  释放获取的SerialSocket.释放端口.
 *  @param  instance    已获取到的SerialSocket实例.
 *  @return 释放操作结果.
 */
bool __SerialSockets::free(SerialSocket *instance){
    /* 查找端口. */
    for ( int n = 0; n < this->serial_socket_list.getSize(); n++ ){
        __SerialSocket *ss_instance = this->serial_socket_list.get(n);
        if ( ss_instance == instance ){
            if ( !this->serial_socket_list.remove(n) ){
                return false;
            }
            delete ss_instance;
            return true;
        }
    }
    return false;
}

/************
 *  @fn     unsigned int __SerialSockets::writePort(int port_number,void *buffer,unsigned int size);
 *  @brief  向指定端口写入数据.
 *  @param  port_number     所使用的端口号.
 *  @param  buffer          待发送的缓冲区.
 *  @param  size            待发送的长度.
 *  @return 实际所发送的长度.
 */
unsigned int __SerialSockets::writePort(int port_number,const void *buffer,unsigned int size){
    if ( this->tx_buffer == nullptr || this->portable == nullptr ){
        return 0;
    }
    /* 计算数据包个数. */
    int n_packet = size / SS_MAX_PAYLOAD_SIZE;
    if ( size % SS_MAX_PAYLOAD_SIZE != 0 ){
        n_packet += 1;
    }
    char *buffer_ptr_curr = (char*)buffer;
    unsigned int size_remain = size;
    unsigned int tx_size = 0;
    for ( ; n_packet > 0; n_packet-- ){
        /* 构造数据帧. */
        SerialSocketFrameHeader *header = (SerialSocketFrameHeader*)(this->tx_buffer);
        header->type = SS_PACKET_TYPE_DATA;
        header->port_number = (uint16_t)port_number;
        header->packet_id = n_packet;
        if ( size_remain > SS_MAX_PAYLOAD_SIZE ){
            header->size = SS_MAX_PAYLOAD_SIZE;
        }else{
            header->size = size_remain;
        }
        memcpy(this->tx_buffer + sizeof(SerialSocketFrameHeader),buffer_ptr_curr,header->size);
        int cal_size = sizeof(SerialSocketFrameHeader) + header->size;
        uint16_t *crc16_field = (uint16_t*)(this->tx_buffer + cal_size);
        *crc16_field = Crypto::crc16((uint8_t*)this->tx_buffer,cal_size);
        /* 发送数据包. */
        if ( !this->portable->takeSemaphore(this->tx_sem_number,-1) ){
            return tx_size;
        }

        this->portable->write(this->tx_buffer,cal_size + 2);

        this->portable->releaseSemaphore(this->tx_sem_number);

        this->tx_resp_code = 0xffff;
        this->writing = true;
        if ( !this->portable->takeSemaphore(this->tx_resp_sem_number,100) ){
            /* 获取信号量失败，超时. */
            this->writing = false;
            return tx_size;
        }
        this->writing = false;
        /* 检查响应是否为RESP_SUCCESS. */
        if ( tx_resp_code != SS_PACKET_RESP_SUCCESS ){
            return tx_size;
        }
        tx_size += header->size;
        buffer_ptr_curr += header->size;
        size_remain -= header->size;
    }
    return tx_size;
}

/************
 *  @fn     void __SerialSockets::eventHandler();
 *  @brief  SerialSockets的事件处理.
 */
void __SerialSockets::eventHandler(){
    if ( this->rx_buffer == nullptr || this->portable == nullptr ){
        return;
    }
    int rx_size = 0;
    int remain_size = 0;
    char *frame_ptr = this->rx_buffer;
    /* 读取数据包. */
    rx_size = this->portable->read(rx_buffer,this->buffer_size);
    remain_size = rx_size;
    /* 自动断帧. */
    do {
        if ( remain_size < (sizeof(SerialSocketFrameHeader) + 2) ){
            return;
        }
        SerialSocketFrameHeader *header = (SerialSocketFrameHeader*)(frame_ptr);
        /* 检查header->size. */
        if ( header->size > 512 ){
            return;
        }
        int frame_size = header->size + sizeof(SerialSocketFrameHeader) + 2;
        if ( (frame_ptr - this->rx_buffer) + frame_size > this->buffer_size ){
            return;
        }
        if ( header->type == SS_PACKET_TYPE_DATA ){
            bool read_cplt_flag = false;
            __SerialSocket *serial_socket = nullptr;
            uint16_t resp_code = SS_PACKET_RESP_SUCCESS;
            /* 数据包. */
            if ( header->size + sizeof(SerialSocketFrameHeader) + 2 <= remain_size ){
                /* 对数据包进行CRC校验. */
                uint16_t *crc_field = (uint16_t*)(frame_ptr + header->size + sizeof(SerialSocketFrameHeader));
                uint16_t crc_cal = Crypto::crc16((uint8_t*)frame_ptr,sizeof(SerialSocketFrameHeader) + header->size);
                if ( *crc_field == crc_cal ){
                    uint16_t port_number = header->port_number;
                    for ( int n = 0; n < this->serial_socket_list.getSize(); n++ ){
                        serial_socket = this->serial_socket_list.get(n);
                        if ( serial_socket->getPortNumber() == port_number ){
                            break;
                        }else{
                            serial_socket = nullptr;
                        }
                    }
                    if ( serial_socket != nullptr ){
                        if ( serial_socket->rx_buffer != nullptr ){
                            if ( serial_socket->expected_packet > 0 && serial_socket->expected_packet != header->packet_id ){
                                /* ID错误.发送错误响应,清空接收长度. */
                                serial_socket->rx_size = 0;
                                resp_code = SS_PACKET_RESP_IDERR;
                            }else{
                                if ( header->size + serial_socket->rx_size <= serial_socket->rx_max_size ){
                                    /* 搬移缓冲区. */
                                    memcpy(serial_socket->rx_buffer + serial_socket->rx_size,frame_ptr + sizeof(SerialSocketFrameHeader),header->size);
                                    serial_socket->rx_size += header->size;
                                    if ( header->packet_id <= 1 ){
                                        /* 最后一块.释放信号量. */
                                        read_cplt_flag = true;
                                    }
                                }else{
                                    /* 截断处理. */
                                    int actually_copy_size = serial_socket->rx_max_size - serial_socket->rx_size;
                                    memcpy(serial_socket->rx_buffer + serial_socket->rx_size,frame_ptr + sizeof(SerialSocketFrameHeader),actually_copy_size);
                                    serial_socket->rx_size += actually_copy_size;
                                    /* 接收已满,释放信号量. */
                                    read_cplt_flag = true;
                                }
                                serial_socket->expected_packet = header->packet_id - 1;
                            }
                        }else{
                            /* 端口未被读取,发送错误响应. */
                            resp_code = SS_PACKET_RESP_NOREAD;
                        }
                    }else{
                        /* 端口未注册,发送错误响应. */
                        resp_code = SS_PACKET_RESP_NOLISTEN;
                    }
                }else{
                    /* CRC校验失败,发送错误响应. */
                    resp_code = SS_PACKET_RESP_CRCERR;
                }
            }else{
                /* 长度校验失败.发送错误响应. */
                resp_code = SS_PACKET_RESP_SIZEERR;
            }
            /* 发送响应. */
            if ( this->resp_buffer != nullptr ){
                SerialSocketFrameHeader *resp_header = (SerialSocketFrameHeader*)(this->resp_buffer);
                resp_header->type = SS_PACKET_TYPE_RESP;
                resp_header->port_number = header->port_number;
                resp_header->packet_id = resp_code;
                resp_header->size = 0;
                uint16_t *crc_field = (uint16_t*)(this->resp_buffer + sizeof(SerialSocketFrameHeader));
                *crc_field = Crypto::crc16((uint8_t*)resp_header,sizeof(SerialSocketFrameHeader));
                if ( this->portable->takeSemaphore(this->tx_sem_number,-1) ){
                    this->portable->write(this->resp_buffer,sizeof(SerialSocketFrameHeader) + 2);
                    this->portable->releaseSemaphore(this->tx_sem_number);
                }
            }
            /* 释放读取线程信号量. */
            if ( read_cplt_flag && (serial_socket != nullptr) ){
                this->portable->releaseSemaphore(serial_socket->rx_sem_number);
                serial_socket->rx_buffer = nullptr;
            }
        }else if ( header->type == SS_PACKET_TYPE_RESP ){
            /* 校验. */
            uint16_t *crc_field = (uint16_t*)(frame_ptr + sizeof(SerialSocketFrameHeader));
            uint16_t crc_cal = Crypto::crc16((uint8_t*)header,sizeof(SerialSocketFrameHeader));
            if ( crc_cal == *crc_field ){
                /* 提取响应返回码. */
                this->tx_resp_code = header->packet_id;
                /* 释放信号量. */
                if ( this->writing ){
                    this->portable->releaseSemaphore(this->tx_resp_sem_number);
                }
            }
        }
        remain_size -= frame_size;
        frame_ptr += frame_size;
    }while ( true );
}

SerialSocket::~SerialSocket(){ }

SerialSockets::~SerialSockets(){ }

SerialSockets *SerialSockets::getInstance(SerialSocketPortable *portable,unsigned int buffer_size){
    if ( portable == nullptr ){
        return nullptr;
    }
    if ( buffer_size < SS_MAX_PAYLOAD_SIZE + sizeof(SerialSocketFrameHeader) + 2 ){
        return nullptr;
    }
    return new __SerialSockets(portable,buffer_size);
}

bool SerialSockets::freeInstance(SerialSocket *instance){
    if ( instance == nullptr ){
        return false;
    }
    delete instance;
    return true;
}
